package cluster

import (
	"bytes"
	"encoding/binary"
	"io"
	"sync"

	"gitee.com/simonxie979/skymeta/protocol"

	"github.com/gogo/protobuf/proto"
)

var headerSize = 4

var headerBufPool = &sync.Pool{
	New: func() any {
		v := make([]byte, headerSize)
		return &v
	},
}

// Pack Encode messages that are communicated between cluster nodes.
func (c *Cluster) Pack(payload *protocol.SSMessage, buf *bytes.Buffer) {
	data, err := proto.Marshal(payload)
	if err != nil {
		c.log.Errorf("Pack", "marshal message failure. err: %v. payload: %#v", err, payload)
		return
	}

	headerBuf := headerBufPool.Get().(*[]byte)
	defer headerBufPool.Put(headerBuf)

	binary.BigEndian.PutUint32(*headerBuf, uint32(len(data)))
	buf.Write(*headerBuf)
	buf.Write(data)
}

// Unpack Decode messages that are communicated between cluster nodes.
func (c *Cluster) Unpack(reader io.Reader) (payload *protocol.SSMessage, err error) {
	headerBuf := headerBufPool.Get().(*[]byte)
	defer headerBufPool.Put(headerBuf)

	_, err = io.ReadAtLeast(reader, *headerBuf, headerSize)
	if err != nil {
		return
	}

	length := binary.BigEndian.Uint32(*headerBuf)
	data := make([]byte, length)

	_, err = io.ReadFull(reader, data)
	if err != nil {
		return
	}

	payload = &protocol.SSMessage{}
	err = proto.Unmarshal(data, payload)
	return
}
